﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using dbPoll_Application.Models;
using System.IO;
using System.Web.Script.Serialization;
using System.Security.Cryptography;
using System.Text.RegularExpressions;

namespace dbPoll_Application.Controllers
{
    public class AccountController : Controller
    {
        public IFormsAuthenticationService FormsService { get; set; }
        public IMembershipService MembershipService { get; set; }

        protected override void Initialize(RequestContext requestContext)
        {
            if (FormsService == null) { FormsService = new FormsAuthenticationService(); }
            if (MembershipService == null) { MembershipService = new AccountMembershipService(); }

            base.Initialize(requestContext);
        }

        private bool IsLocalUrl(string url)
        {
            if (string.IsNullOrEmpty(url))
            {
                return false;
            }

            Uri absoluteUri;
            if (Uri.TryCreate(url, UriKind.Absolute, out absoluteUri))
            {
                return String.Equals(this.Request.Url.Host, absoluteUri.Host, StringComparison.OrdinalIgnoreCase);
            }
            else
            {
                bool isLocal = !url.StartsWith("http:", StringComparison.OrdinalIgnoreCase)
                    && !url.StartsWith("https:", StringComparison.OrdinalIgnoreCase)
                    && Uri.IsWellFormedUriString(url, UriKind.Relative);
                return isLocal;
            }
        }

        public ActionResult LogOn()
        {
            if (User.Identity.IsAuthenticated)
                return Redirect(GetRedirectURL(User.Identity.Name));

            var model = new LogOnModel();
            if (Request.QueryString["ReturnUrl"] != null)
                model.ReturnUrl = Request.QueryString["ReturnUrl"];
            return View(model);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult LogOn(LogOnModel model)
        {
            if (ModelState.IsValid)
            {
                if (MembershipService.ValidateUser(model.UserName, model.Password))
                {
                    User user = UserRepository.GetUserByUsername(model.UserName);
                    if (user.CreationDate == user.LastPasswordChangedDate && !user.IsGeneric)
                    {
                        TempData["username"] = model.UserName;
                        TempData["password"] = model.Password;
                        TempData["rememberme"] = model.RememberMe;
                        model.Url = Url.Action("FirstLogOn", "Account");
                        return PartialView("LogOnContainer", model);
                    }
                    if ((user.Roles.Contains(RoleRepository.GetRoleByName("Poll Administrator")) && DateTime.Now < user.AccountExpiryDate) ||
                        (!user.Roles.Contains(RoleRepository.GetRoleByName("Poll Administrator"))))
                    {
                        FormsService.SignIn(model.UserName, model.RememberMe);
                    }
                    else
                    {
                        ModelState.AddModelError("", "Error, that account has expired");
                        return PartialView("LogOnContainer", model);
                    }
                    if (IsLocalUrl(model.ReturnUrl))
                    {
                        model.Url = model.ReturnUrl;
                        return PartialView("LogOnContainer", model);
                    }
                    else
                    {
                        model.Url = GetRedirectURL(model.UserName);
                        return PartialView("LogOnContainer", model);
                    }
                }
                else
                {
                    ModelState.AddModelError("", "The current password is incorrect or the username is invalid.");
                }
            }
            return View("LogOnContainer", model);
        }

        public ActionResult ForgotPassword()
        {
            return View();
        }

        private string GetRedirectURL(string username)
        {
            User user = UserRepository.GetUserByUsername(username);
            if (user.Roles.Contains(RoleRepository.GetRoleByName("System Administrator")))
                return Url.Action("Index", "SystemReport");
            else if (user.Roles.Contains(RoleRepository.GetRoleByName("Poll Administrator")) ||
                user.Roles.Contains(RoleRepository.GetRoleByName("Poll Creator")) ||
                user.Roles.Contains(RoleRepository.GetRoleByName("Poll Master")))
                return Url.Action("Index", "Poll");
            else
                return Url.Action("Index", "Respond");
        }

        [HttpPost]
        public ActionResult ForgotPassword(ForgotPasswordModel model)
        {
            if (ModelState.IsValid)
            {
                if (model.Status == ForgotPasswordStatus.ForgotPasswordRespondToSecurityQuestion)
                {
                    User user = UserRepository.GetUserByUsername(model.Username);
                    model.SecurityQuestion = user.PasswordQuestion;
                    String securityAnswer = user.PasswordAnswer;
                    OracleMembershipProvider provider = (OracleMembershipProvider)Membership.Providers["OracleMembershipProvider"];
                    if (provider.ValidatePassword(model.SecurityAnswer, securityAnswer))
                    {
                        MembershipUser membershipUser = Membership.GetUser(model.Username);
                        model.Url = Url.Action("ResetPassword", "Account");
                        TempData["username"] = model.Username;
                        TempData["password"] = membershipUser.ResetPassword();
                        return PartialView("ForgotPasswordContainer", model);
                    }
                    else
                    {
                        ModelState.AddModelError("", "Error, the provided answer is incorrect.");
                        return PartialView("ForgotPasswordContainer", model);
                    }
                }
                else if (model.Status == ForgotPasswordStatus.ForgotPasswordGetSecurityQuestion)
                {
                    User user = UserRepository.GetUserByUsername(model.Username);
                    if (user == null)
                    {
                        ModelState.AddModelError("", "Error, the username does not match any user in our records");
                    }
                    model.SecurityQuestion = user.PasswordQuestion;
                    return PartialView("ForgotPasswordContainer", model);
                }
                else if (model.Status == ForgotPasswordStatus.ForgotPasswordUnknownSecurityAnswer)
                {
                    if (String.IsNullOrEmpty(model.Username))
                    {
                        ModelState.AddModelError("", "Error, The entered username is not registered for use with dbPoll.");
                        return PartialView("ForgotPasswordContainer", model);
                    }
                    MembershipUser user = Membership.GetUser(model.Username);
                    if (user == null)
                    {
                        ModelState.AddModelError("", "Error, The entered username is not registered for use with dbPoll.");
                        return PartialView("ForgotPasswordContainer", model);
                    }
                    Helpers.Email.SendTemplatedEmail("donotreplydbpoll@gmail.com",
                                user.Email,
                                "dbPoll Account Details",
                                Url.Action("GenericEmail", "Email", 0, "http") +
                                "?username=" + HttpUtility.UrlEncode(user.UserName) +
                                "&password=" + HttpUtility.UrlEncode(user.ResetPassword()) +
                                "&heading=" + HttpUtility.UrlEncode("dbPoll Account Details") +
                                "&msg=" + HttpUtility.UrlEncode("Your dbPoll Account Details are as follows: "));
                }
                else if (model.Status == ForgotPasswordStatus.ForgotUsernameAndPassword)
                {
                    String username = Membership.GetUserNameByEmail(model.Email);
                    if (String.IsNullOrEmpty(username))
                    {
                        ModelState.AddModelError("", "Error, The entered email is not registered for use with dbPoll.");
                        return PartialView("ForgotPasswordContainer", model);
                    }
                    MembershipUser user = Membership.GetUser(username);
                    Helpers.Email.SendTemplatedEmail("donotreplydbpoll@gmail.com",
                               user.Email,
                               "dbPoll Account Details",
                               Url.Action("GenericEmail", "Email", 0, "http") +
                               "?username=" + HttpUtility.UrlEncode(user.UserName) +
                               "&password=" + HttpUtility.UrlEncode(user.ResetPassword()) +
                               "&heading=" + HttpUtility.UrlEncode("dbPoll Account Details") +
                               "&msg=" + HttpUtility.UrlEncode("Your dbPoll Account Details are as follows: "));
                }
            }
            return PartialView("ForgotPasswordContainer", model);
        }

        [Authorize]
        public ActionResult LogOff()
        {
            FormsService.SignOut();
            return RedirectToAction("LogOn", "Account");
        }

        public ActionResult ResetPassword()
        {
            ResetPasswordModel model = new ResetPasswordModel();
            model.UserName = TempData["username"].ToString();
            model.OldPassword = TempData["password"].ToString();
            return View(model);
        }

        [HttpPost]
        public ActionResult ResetPassword(ResetPasswordModel model)
        {
            if (ModelState.IsValid)
            {
                Boolean success = true;
                User user = UserRepository.GetUserByUsername(model.UserName);
                if (user == null)
                {
                    ModelState.AddModelError("", "The supplied details are invalid.");
                    success = false;
                }
                else if (!MembershipService.ChangePassword(model.UserName, model.OldPassword, model.NewPassword))
                {
                    ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
                    success = false;
                }
                if (success)
                {
                    FormsService.SignIn(model.UserName, false);
                    model.Url = GetRedirectURL(model.UserName);
                    return PartialView("ResetPasswordContainer", model);
                }
            }
            return PartialView("ResetPasswordContainer", model);
        }

        public ActionResult FirstLogOn()
        {
            FirstLogOnModel model = new FirstLogOnModel();
            if (TempData["username"] != null && TempData["password"] != null && TempData["rememberme"] != null)
            {
                model.UserName = TempData["username"].ToString();
                model.OldPassword = TempData["password"].ToString();
                model.RememberMe = Boolean.Parse(TempData["rememberme"].ToString());
            }
            return View(model);
        }

        [HttpPost]
        public ActionResult FirstLogOn(FirstLogOnModel model)
        {
            if (ModelState.IsValid)
            {
                Boolean success = true;
                User user = UserRepository.GetUserByUsername(model.UserName);
                MembershipUser membershipUser = Membership.GetUser(model.UserName);
                if (user == null)
                {
                    ModelState.AddModelError("", "The supplied details are invalid.");
                    success = false;
                }
                else if (!membershipUser.ChangePasswordQuestionAndAnswer(model.OldPassword, model.SecurityQuestion, model.SecurityAnswer))
                {
                    ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
                    success = false;
                }
                else if (!MembershipService.ChangePassword(model.UserName, model.OldPassword, model.NewPassword))
                {
                    ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
                    success = false;
                }
                if (success)
                {
                    FormsService.SignIn(model.UserName, model.RememberMe);
                    model.Url = GetRedirectURL(model.UserName);
                    return PartialView("FirstLogOnContainer", model);
                }
            }
            return PartialView("FirstLogOnContainer", model);
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        public AccountManagerModel DefaultMake()
        {
            var model = new AccountManagerModel();
            model.GenericEmails = new List<GenericEmail>();
            model.IsGeneric = false;
            model.IsEditable = true;
            model.IsNew = true;
            model.UserName = String.Empty;
            if (User.IsInRole("System Administrator"))
            {
                model.AccountExpiryDate = DateTime.Now.AddYears(1);
                model.SelectedRole = "Poll Administrator";
                model.InUsersGroup = new List<User>();
                model.NotInUsersGroup = UserRepository.GetUsersByRoleName("Poll Administrator").ToList();
            }
            else if (User.IsInRole("Poll Administrator"))
                model.SelectedRole = "Poll Creator";
            else if (User.IsInRole("Poll Creator"))
                model.SelectedRole = "Poll Master";
            else if (User.IsInRole("Poll Master"))
                model.SelectedRole = "Poll User";
            return model;
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        public ActionResult AccountManager(String username, String role)
        {
            if (username == null && role == null)
            {
                return View(DefaultMake());
            }
            else if (username != null)
            {
                User user = UserRepository.GetUserByUsername(username);
                var model = new AccountManagerModel();
                model.UserName = user.UserName;
                model.FirstName = user.FirstName;
                model.LastName = user.LastName;
                model.City = user.City;
                model.Country = user.Country;
                model.Email = user.Email;
                model.Gender = user.Gender;
                model.GenericEmails = user.GenericEmails.ToList();
                model.IsGeneric = user.IsGeneric;
                model.Organisation = user.Organisation;
                model.Position = user.Position;
                model.AccountExpiryDate = user.AccountExpiryDate;
                model.IsEditable = false;
                model.IsNew = false;
                if (user.Roles.Contains(RoleRepository.GetRoleByName("System Administrator")))
                    model.SelectedRole = "Poll Administrator";
                else if (user.Roles.Contains(RoleRepository.GetRoleByName("Poll Administrator")))
                {
                    model.SelectedRole = "Poll Administrator";
                    model.InUsersGroup = UserRepository.GetPollAdministratorsInUsersGroup(model.UserName).ToList<User>();
                    model.NotInUsersGroup = UserRepository.GetPollAdministratorsNotInUsersGroup(model.UserName).ToList<User>();
                }
                else if (user.Roles.Contains(RoleRepository.GetRoleByName("Poll Creator")))
                    model.SelectedRole = "Poll Creator";
                else if (user.Roles.Contains(RoleRepository.GetRoleByName("Poll Master")))
                    model.SelectedRole = "Poll Master";
                else if (user.Roles.Contains(RoleRepository.GetRoleByName("Poll User")))
                    model.SelectedRole = "Poll User";
                return View(model);
            }
            else
            {
                String[] roles = { "Poll Administrator", "Poll Creator", "Poll Master", "Poll User" };
                if (!roles.Contains(role)) return View(DefaultMake());
                var user = UserRepository.GetUserByUsername(User.Identity.Name);
                if (!user.Roles.Contains(RoleRepository.GetRoleByName("System Administrator")) && role == "Poll Administrator")
                    return View(DefaultMake());
                if (!user.Roles.Contains(RoleRepository.GetRoleByName("Poll Administrator")) && role == "Poll Creator")
                    return View(DefaultMake());
                if (!user.Roles.Contains(RoleRepository.GetRoleByName("Poll Creator")) && role == "Poll Master")
                    return View(DefaultMake());
                if (!user.Roles.Contains(RoleRepository.GetRoleByName("Poll Master")) && role == "Poll User")
                    return View(DefaultMake());
                var model = new AccountManagerModel();
                model.GenericEmails = new List<GenericEmail>();
                model.IsGeneric = false;
                model.IsEditable = true;
                model.IsNew = true;
                model.SelectedRole = role;
                if (model.SelectedRole == "Poll Administrator")
                {
                    model.AccountExpiryDate = DateTime.Now.AddYears(1);
                    model.InUsersGroup = new List<User>();
                    model.NotInUsersGroup = UserRepository.GetUsersByRoleName("Poll Administrator").ToList();
                }
                return View(model);
            }
        }

        [Authorize(Roles="System Administrator,Poll Master")]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult AccountManager(AccountManagerModel model)
        {
            if (model.GenericEmails == null) model.GenericEmails = new List<GenericEmail>();
            if (ModelState.IsValid)
            {
                if (model.IsEditable)
                {
                    String password = Membership.GeneratePassword(8, 0);
                    MembershipCreateStatus createStatus = MembershipService.
                        CreateUser(model.UserName, password, 
                        model.IsGeneric == false ? model.Email : Membership.GeneratePassword(8, 0), model.IsGeneric);
                    if (createStatus == MembershipCreateStatus.Success)
                    {
                        User user = UserRepository.GetUserByUsername(model.UserName);
                        user.IsGeneric = model.IsGeneric;
                        user.GenericEmails = model.GenericEmails;
                        user.FirstName = model.FirstName;
                        user.LastName = model.LastName;
                        user.Gender = model.Gender;
                        user.Position = model.Position;
                        user.City = model.City;
                        user.Country = model.Country;
                        user.Organisation = model.Organisation;
                        user.AccountExpiryDate = model.AccountExpiryDate;
                        if (model.SelectedRole != "Poll Administrator")
                        {
                            model.AccountExpiryDate = DateTime.MaxValue;
                        }
                        if (model.SelectedRole == "Poll Administrator")
                        {
                            user.ClientCodes.Add(new ClientCode(user));
                            model.InUsersGroup = new List<User>();
                            model.NotInUsersGroup = new List<User>();
                            User owner = UserRepository.GetUserByUsername(User.Identity.Name);
                            model.NotInUsersGroup.AddRange(UserRepository.GetUsersUserCanManage(User.Identity.Name).
                                Where(u=>u.Roles.Contains(RoleRepository.GetRoleByName("Poll Administrator"))));
                        }
                        else
                        {
                            User creator = UserRepository.GetUserByUsername(User.Identity.Name);
                            foreach (ClientCode code in creator.ClientCodes)
                            {
                                if (!user.ClientCodes.Contains(code))
                                {
                                    user.ClientCodes.Add(code);
                                }
                            }
                        }
                        UserRepository.Update(user);
                        Roles.AddUserToRole(model.UserName, model.SelectedRole);
                        Role selectedRole = RoleRepository.GetRoleByName(model.SelectedRole);
                        foreach (Role role in selectedRole.InheritedRoles)
                        {
                            if (!user.Roles.Contains(role))
                            {
                                Roles.AddUserToRole(model.UserName, role.RoleName);
                            }
                        }

                        if (model.IsGeneric)
                        {
                            Helpers.Email.SendTemplatedGenericEmails("donotreplydbpoll@gmail.com",
                                user.GenericEmails.ToList<GenericEmail>(),
                                "dbPoll Account Details",
                                Url.Action("GenericEmail", "Email", 0, "http") +
                                "?username=" + HttpUtility.UrlEncode(user.UserName) +
                                "&password=" + HttpUtility.UrlEncode(password) +
                                "&heading=" + HttpUtility.UrlEncode("Welcome to dbPoll") +
                                "&msg=" + HttpUtility.UrlEncode("You have just been invited to use dbPoll.  Your details needed to sign-in to dbPoll are as follows: "));
                        }
                        else
                        {
                            Helpers.Email.SendTemplatedEmail("donotreplydbpoll@gmail.com",
                                user.Email,
                                "dbPoll Account Details",
                                Url.Action("GenericEmail", "Email", 0, "http") +
                                "?username=" + HttpUtility.UrlEncode(user.UserName) +
                                "&password=" + HttpUtility.UrlEncode(password) +
                                "&heading=" + HttpUtility.UrlEncode("Welcome to dbPoll") +
                                "&msg=" + HttpUtility.UrlEncode("You have just been invited to use dbPoll.  Your details needed to sign-in to dbPoll are as follows: "));
                          }
                        model.IsNew = false;
                        model.IsEditable = false;
                        return PartialView("AccountManagerContainer", model);
                    }
                    else
                    {
                        ModelState.AddModelError("", "Error, " + AccountValidation.ErrorCodeToString(createStatus));
                        return PartialView("AccountManagerContainer", model);
                    }
                }
                else
                {
                    User user = UserRepository.GetUserByUsername(model.UserName);

                    if (model.SelectedRole == "Poll Administrator")
                    {
                        user.ClientCodes.Add(new ClientCode(user));
                        user.City = model.City;
                        user.Country = model.Country;
                        user.FirstName = model.FirstName;
                        user.Gender = model.Gender;
                        user.LastName = model.LastName;
                        user.Organisation = model.Organisation;
                        user.Position = model.Position;
                        model.IsEditable = true;
                        model.InUsersGroup = UserRepository.GetPollAdministratorsInUsersGroup(model.UserName).ToList<User>();
                        model.NotInUsersGroup = UserRepository.GetPollAdministratorsNotInUsersGroup(model.UserName).ToList<User>();
                    }
                    else 
                    {
                        User creator = UserRepository.GetUserByUsername(User.Identity.Name);
                        foreach (ClientCode code in creator.ClientCodes)
                        {
                            if (!user.ClientCodes.Contains(code))
                            {
                                user.ClientCodes.Add(code);
                            }
                        }
                    }

                    if (!user.Roles.Contains(RoleRepository.GetRoleByName(model.SelectedRole)))
                    {
                        Roles.AddUserToRole(model.UserName, model.SelectedRole);
                    }
                    Role selectedRole = RoleRepository.GetRoleByName(model.SelectedRole);
                    foreach (Role role in selectedRole.InheritedRoles)
                    {
                        if (!user.Roles.Contains(RoleRepository.GetRoleByName(role.RoleName)))
                        {
                            Roles.AddUserToRole(model.UserName, role.RoleName);
                        }
                    }

                    user.AccountExpiryDate = model.AccountExpiryDate == DateTime.MinValue ? DateTime.Now.AddYears(1) : model.AccountExpiryDate;
                    model.AccountExpiryDate = user.AccountExpiryDate;
                    user.IsDeleted = false;
                    if (UserRepository.Update(user))
                    {
                        model.IsNew = false;
                        return PartialView("AccountManagerContainer", model);
                    }
                }
            }
            return PartialView("AccountManagerContainer", model);
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        public String EmailIsValid(String email)
        {
            User user = UserRepository.GetUserByEmail(email);
            if (user == null)
            {
                return "valid";
            }
            else if (user.Roles.Count == 1 && user.Roles.Contains(RoleRepository.GetRoleByName("Poll User")))
            {
                return "user";
            }
            else 
            {
                return "invalid";
            }
        }

        public Boolean ResetPasswordByUsername(String username)
        {
            MembershipUser user = Membership.GetUser(username);
            if (user == null)
            {
                return false;
            }
            try
            {
                Helpers.Email.SendTemplatedEmail("donotreplydbpoll@gmail.com",
                user.Email,
                "dbPoll Account Details",
                Url.Action("GenericEmail", "Email", 0, "http") +
                "?username=" + HttpUtility.UrlEncode(user.UserName) +
                "&password=" + HttpUtility.UrlEncode(user.ResetPassword()) +
                "&heading=" + HttpUtility.UrlEncode("dbPoll Account Details") +
                "&msg=" + HttpUtility.UrlEncode("Your dbPoll Account Details are as follows: "));
            }
            catch (Exception e)
            {
                return false;
            }
            return true;
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        public Boolean UserNameIsValid(String username)
        {
            return UserRepository.GetUserByUsername(username) == null;
        }

        [Authorize(Roles = "System Administrator")]
        public ViewResult AddPollAdministratorToGroup(String username1, String username2)
        {
            ClientCode code1 = ClientCodeRepository.GetClientCodeByUserName(username1);
            ClientCode code2 = ClientCodeRepository.GetClientCodeByUserName(username2);
            List<User> users1 = UserRepository.GetUsersByClientCode(code1).ToList<User>();
            List<User> users2 = UserRepository.GetUsersByClientCode(code2).ToList<User>();
            foreach (User user1 in users1)
            {
                if ((!user1.Roles.Contains(RoleRepository.GetRoleByName("Poll Administrator"))
                    && !user1.Roles.Contains(RoleRepository.GetRoleByName("System Administrator")))
                    || user1.UserName == username1)
                {
                    user1.ClientCodes.Add(code2);
                    UserRepository.Update(user1);
                }
            }
            foreach (User user2 in users2)
            {
                if ((!user2.Roles.Contains(RoleRepository.GetRoleByName("Poll Administrator"))
                    && !user2.Roles.Contains(RoleRepository.GetRoleByName("System Administrator")))
                    || user2.UserName == username2)
                {
                    user2.ClientCodes.Add(code1);
                    UserRepository.Update(user2);
                }
            }
            AccountManagerModel model = new AccountManagerModel();
            model.InUsersGroup = UserRepository.GetPollAdministratorsInUsersGroup(username2).ToList<User>();
            model.NotInUsersGroup = UserRepository.GetPollAdministratorsNotInUsersGroup(username2).ToList<User>();
            return View("PollAdministratorGroups", model);
        }

        [Authorize(Roles="System Administrator,Poll Master")]
        public ViewResult GetUserDetails(String email, String selectedrole)
        {
            User user = UserRepository.GetUserByEmail(email);
            AccountManagerModel model = new AccountManagerModel();
            model.UserName = user.UserName;
            model.Email = user.Email;
            model.FirstName = user.FirstName;
            model.LastName = user.LastName;
            model.Gender = user.Gender;
            model.Organisation = user.Organisation;
            model.Position = user.Position;
            model.City = user.City;
            model.Country = user.Country;
            model.SelectedRole = selectedrole;
            model.GenericEmails = new List<GenericEmail>();
            model.IsEditable = false;
            model.IsNew = true;
            return View("AccountManagerContainer", model);
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        public ViewResult GetNewUserDetails(String username, String email, String firstname, String lastname, 
            String organisation, String position, String city, String country, String selectedrole, String gender,
            String isgeneric)
        {
            AccountManagerModel model = new AccountManagerModel();
            model.UserName = username;
            model.Email = email;
            model.FirstName = firstname;
            model.LastName = lastname;
            model.Organisation = organisation;
            model.Position = position;
            model.City = city;
            model.Country = country;
            model.SelectedRole = selectedrole;
            model.IsEditable = true;
            model.IsNew = true;
            model.IsGeneric = isgeneric == "true" ? true : false;
            model.GenericEmails = new List<GenericEmail>();
            if (gender == "Male") model.Gender = Gender.Male;
            else if (gender == "Female") model.Gender = Gender.Female;
            return View("AccountManagerContainer", model);
        }

        [Authorize(Roles="Poll Master")]
        public ViewResult BlankEditorRow()
        {
            return View("GenericEmailRow", new GenericEmail());
        }

        [Authorize(Roles = "Poll Master")]
        public ViewResult FilledEditorRow(String email)
        {
            return View("GenericEmailRow", new GenericEmail(email.Trim()));
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        public Boolean DeleteUserRow(String username)
        {
            User user = UserRepository.GetUserByUsername(username);
            if (user == null) return false;
            user.IsDeleted = true;
            return UserRepository.Update(user);
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        public string AsyncUpload()
        {
            List<String> result = new List<String>();
            using (StreamReader CsvReader = new StreamReader(Request.Files[0].InputStream))
            {
                string inputLine = "";
                inputLine = CsvReader.ReadToEnd();
                MatchCollection mc = Regex.Matches(inputLine, "([a-zA-Z0-9_\\-\\.]+)@([a-zA-Z0-9_\\-\\.]+)\\..([a-zA-Z]{2,5})");
                for (int i=0;i < mc.Count; i++)
                {
                    result.Add(mc[i].ToString());
                }
                CsvReader.Close();
            }
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            return serializer.Serialize(result);
        }

        [Authorize]
        public ActionResult ChangePassword()
        {
            ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
            return View();
        }

        [Authorize]
        [HttpPost]
        public ActionResult ChangePassword(ChangePasswordModel model)
        {
            if (ModelState.IsValid)
            {
                if (MembershipService.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword))
                {
                    return PartialView("ChangePasswordContainer", model);
                }
                else
                {
                    ModelState.AddModelError("", "Error, the current password is incorrect or the new password is invalid.");
                    return PartialView("ChangePasswordContainer", model);
                }
            }
            ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
            return PartialView("ChangePasswordContainer", model);
        }

        [Authorize]
        public ActionResult MyAccount()
        {
            return View();
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        public ActionResult ManageAccounts()
        {
            var users = UserRepository.GetUsersUserCanManage(User.Identity.Name);
            ManageAccountsModel model = new ManageAccountsModel();
            model.Users = users;
            model.SelectedRoleName = String.Empty;
            model.Roles = new List<Role>();
            model.SelectedOrderByFilter = String.Empty;
            model.SortFilters = GetManageAccountsFilterOptions();
            model.Roles = GetManageAccountsRoleOptions();
            return View(model);
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        public ViewResult FilterAccounts(String rolename, String filter, String demographic, String organisation, String location)
        {
            var users = UserRepository.GetUsersUserCanManage(User.Identity.Name, rolename, demographic, organisation, location);
            ManageAccountsModel model = new ManageAccountsModel();
            model.Users = users;
            model.SelectedRoleName = rolename;
            model.SelectedOrderByFilter = filter;
            model.SelectedDemographic = demographic;
            model.SelectedLocation = location;
            model.SelectedOrganisation = organisation;
            model.SortFilters = GetManageAccountsFilterOptions();
            model.Roles = GetManageAccountsRoleOptions();
            if (filter == "Username: A To Z")
            {
                model.Users = model.Users.OrderBy(x => x.UserName).ToList<User>();
            }
            else if (filter == "Username: Z To A")
            {
                model.Users = model.Users.OrderByDescending(x => x.UserName).ToList<User>();
            }
            else if (filter == "First Name: A To Z")
            {
                model.Users = model.Users.OrderBy(x => x.FirstName).ToList<User>();
            }
            else if (filter == "First Name: Z To A")
            {
                model.Users = model.Users.OrderByDescending(x => x.FirstName).ToList<User>();
            }
            else if (filter == "Last Name: A To Z")
            {
                model.Users = model.Users.OrderBy(x => x.LastName).ToList<User>();
            }
            else if (filter == "Last Name: Z To A")
            {
                model.Users = model.Users.OrderByDescending(x => x.LastName).ToList<User>();
            }
            else if (filter == "Creation Date: Most Recent First")
            {
                model.Users = model.Users.OrderByDescending(x => x.CreationDate).ToList<User>();
            }
            else if (filter == "Creation Date: Oldest First")
            {
                model.Users = model.Users.OrderBy(x => x.CreationDate).ToList<User>();
            }
            else if (filter == "Last Login Date: Most Recent First")
            {
                model.Users = model.Users.OrderByDescending(x => x.LastLoginDate).ToList<User>();
            }
            else if (filter == "Last Login Date: Oldest First")
            {
                model.Users = model.Users.OrderBy(x => x.LastLoginDate).ToList<User>();
            }
            return View("UserListAll", model);
        }

        [Authorize]
        private List<Role> GetManageAccountsRoleOptions()
        {
            List<Role> roleOptions = new List<Role>();
            if (User.IsInRole("System Administrator"))
            {
                roleOptions.Add(RoleRepository.GetRoleByName("Poll Administrator"));
            }
            else if (User.IsInRole("Poll Administrator"))
            {
                roleOptions = RoleRepository.GetRolesInheritedByRole("Poll Administrator").ToList<Role>();
            }
            else if (User.IsInRole("Poll Creator"))
            {
                roleOptions = RoleRepository.GetRolesInheritedByRole("Poll Creator").ToList<Role>();
            }
            else if (User.IsInRole("Poll Master"))
            {
                roleOptions = RoleRepository.GetRolesInheritedByRole("Poll Master").ToList<Role>();
            }
            return roleOptions;
        }

        [Authorize(Roles = "System Administrator,Poll Master")]
        private List<SelectListItem> GetManageAccountsFilterOptions()
        {
            List<SelectListItem> filterOptions = new List<SelectListItem>();
            filterOptions.Add(new SelectListItem { Text = "Username: A To Z", Value = "Username: A To Z" });
            filterOptions.Add(new SelectListItem { Text = "Username: Z To A", Value = "Username: Z To A" });
            filterOptions.Add(new SelectListItem { Text = "First Name: A To Z", Value = "First Name: A To Z" });
            filterOptions.Add(new SelectListItem { Text = "First Name: Z To A", Value = "First Name: Z To A" });
            filterOptions.Add(new SelectListItem { Text = "Last Name: A To Z", Value = "Last Name: A To Z" });
            filterOptions.Add(new SelectListItem { Text = "Last Name: Z To A", Value = "Last Name: Z To A" });
            filterOptions.Add(new SelectListItem { Text = "Creation Date: Most Recent First", Value = "Creation Date: Most Recent First" });
            filterOptions.Add(new SelectListItem { Text = "Creation Date: Oldest First", Value = "Creation Date: Oldest First" });
            filterOptions.Add(new SelectListItem { Text = "Last Login Date: Most Recent First", Value = "Last Login Date: Most Recent First" });
            filterOptions.Add(new SelectListItem { Text = "Last Login Date: Oldest First", Value = "Last Login Date: Oldest First" });
            return filterOptions;
        }

        [Authorize]
        public ActionResult ChangeSecurityQuestionAndAnswer()
        {
            return View();
        }

        [Authorize]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult ChangeSecurityQuestionAndAnswer(ChangeSecurityQuestionAndAnswerModel model)
        {
            if (ModelState.IsValid)
            {
                MembershipUser user = Membership.GetUser(User.Identity.Name);
                if (user.ChangePasswordQuestionAndAnswer(model.Password, model.SecurityQuestion, model.SecurityAnswer))
                {
                    return PartialView("ChangeSecurityQuestionAndAnswerContainer", model);
                }
                else
                {
                    ModelState.AddModelError("", "Error, the supplied password does not match our records.");
                    return PartialView("ChangeSecurityQuestionAndAnswerContainer", model);
                }
            }
            return PartialView("ChangeSecurityQuestionAndAnswerContainer", model);
        }

        [Authorize]
        public ActionResult ChangePersonalDetails()
        {
            User user = UserRepository.GetUserByUsername(User.Identity.Name);
            ChangePersonalDetailsModel model = new ChangePersonalDetailsModel();
            model.City = user.City;
            model.Gender = user.Gender;
            model.Country = user.Country;
            model.Email = user.Email;
            model.FirstName = user.FirstName;
            model.LastName = user.LastName;
            model.Position = user.Position;
            ViewData["status"] = String.Empty;
            return View(model);
        }

        [Authorize]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult ChangePersonalDetails(ChangePersonalDetailsModel model)
        {
            if (ModelState.IsValid)
            {
                User user = UserRepository.GetUserByUsername(User.Identity.Name);
                user.Email = model.Email;
                user.FirstName = model.FirstName;
                user.LastName = model.LastName;
                user.Gender = model.Gender;
                user.Position = model.Position;
                user.City = model.City;
                user.Country = model.Country;

                if (UserRepository.Update(user))
                {
                    return PartialView("ChangePersonalDetailsContainer", model);
                }
                else
                {
                    ModelState.AddModelError("", "Error, the supplied details are invalid");
                }
            }
            return PartialView("ChangePersonalDetailsContainer", model);
        }
    }
}
